package view.overlay;

import inventory.EquipLocation;
import item.TakeableItem;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import view.drawing.DrawState;
import view.drawing.StaticDrawState;
import entity.Entity;

public class InventoryOverlay extends PassiveOverlay {
	
	private Entity mEntity;
	
	private int mPaddingTop;
	private int mPaddingBottom;
	private int mPaddingLeft;
	private int mPaddingRight;
	
	private Rectangle mBounds;
	
	private EnumMap<EquipLocation, Rectangle> mEquipBounds;
	
	// Buttons for the inventory
	private CopyOnWriteArrayList<Button> mInvButtons;
	
	private List<InventoryActionListener> mListeners;
	
	private boolean mIsFullVisible;
	
	private Button mToggleButton;
	private Button mInvNextPageButton;
	private Button mInvPrevPageButton;
	
	private Image mBackgroundImage;
	
	private Rectangle mInvRect;
	private Rectangle mEquipRect;
	
	private Map<TakeableItem, MouseListener> mInvItems;
	private EnumMap<EquipLocation, TakeableItem> mEquippedItems;

	private Map<EquipLocation, MouseListener> mEquippedListeners;
	
	public InventoryOverlay() {
		
		mBounds = new Rectangle(0, 0, this.getWidth(), this.getHeight());
		
		mEquipBounds = new EnumMap<EquipLocation, Rectangle>(EquipLocation.class);
		mInvButtons = new CopyOnWriteArrayList<Button>();
		
		
		// Map for takeableitems
		mInvItems = new HashMap<TakeableItem, MouseListener>();
		
		// Create a list of inventory listeners
		mListeners = new ArrayList<InventoryActionListener>();
		
		mPaddingLeft = 100;
		mPaddingRight = 100;
		mPaddingTop = 100;
		mPaddingBottom = 100;
		
		mIsFullVisible = false;
		
		mInvNextPageButton = new Button("Next");
		mInvPrevPageButton = new Button("Prev");
		
		mToggleButton = new Button("Inventory");
		
	}

	@Override
	protected void paint(Graphics g) {
		
//		g.setColor(new Color(255, 255, 255, 0));
//		g.clearRect(0, 0, this.getWidth(), this.getHeight());
		
		// Always want to draw the button at the top
		mToggleButton.draw(g);
		
		// Only draw the full inventory if it is visible
		if (mIsFullVisible) {
			
			// If we have a background image, draw it, scaled to fit, the bounding rect
			if (mBackgroundImage != null) {
				g.drawImage(mBackgroundImage, mBounds.x, mBounds.y,
							mBounds.width, mBounds.height, null);
			}
			else {
				// Fill it with a background color
				g.setColor(new Color(179, 136, 69, 175));
				g.fillRect(mBounds.x, mBounds.y,
							mBounds.width, mBounds.height);
			}
			
			
			// Draw the borders
			g.setColor(new Color(106, 69, 10));
			
			// Draw Equipment Rectangle
			g.draw3DRect(mEquipRect.x,
					mEquipRect.y,
					mEquipRect.width,
					mEquipRect.height,
					true);
			
			// Draw the Inventory Rectangle
			g.draw3DRect(mInvRect.x,
					mInvRect.y,
					mInvRect.width,
					mInvRect.height,
					true);
			
			
			// Draw the text
			String invString = "Inventory";
			String eqpString = "Equipment";
			
			// Set the color to white for text
			g.setColor(Color.WHITE);
			
			// Draw the text for the inventory
			Rectangle2D size = g.getFontMetrics().getStringBounds(invString, g);
			g.drawString(invString,
						(int)(mInvRect.x + mInvRect.getWidth() / 2 - size.getWidth() / 2),
						(int)(mInvRect.y + size.getHeight() / 2) + 10);
							
			// Draw the text for the equipment
			size = g.getFontMetrics().getStringBounds(eqpString, g);
			g.drawString(eqpString,
					(int)(mEquipRect.x + mEquipRect.getWidth() / 2 - size.getWidth() / 2),
					(int)(mEquipRect.y + size.getHeight() / 2) + 10);
			
			// Draw the equip boxes
			for (EquipLocation loc : EquipLocation.values()) {
				// Get the rect
				Rectangle rect = mEquipBounds.get(loc);
				
				if (rect == null) continue;
				
				g.draw3DRect(rect.x, rect.y, rect.width, rect.height, true);
				
				// Now draw the images for the items
				
				if (mEntity != null) {
					
				}
				if (mEquippedItems != null) {
					if (mEquippedItems.containsKey(loc)) {
						// we have an item at this location
						DrawState<TakeableItem> ds = new StaticDrawState<TakeableItem>(mEquippedItems.get(loc));

						ds.draw(g, rect);	
					}
				}
				
			}
			

			// Draw all the inventory items
			for (Button b : mInvButtons) {
				b.draw(g);
			}
			
			// Draw the page buttons
			mInvNextPageButton.draw(g);
			mInvPrevPageButton.draw(g);
		}
	}
	
	public void setToggleButtonListener(MouseListener listener) {
		mToggleButton.setListener(listener);
	}
	
	public void setInventoryItems(Map<TakeableItem, MouseListener> items) {
		mInvItems = items;
		
		mInvButtons.clear();
		
		calculateBounds();
		this.invalidate();
	}
	
	@Override
	public void onMouseClicked(MouseEvent e) {
		Point p = e.getPoint();
		
		if (mToggleButton.contains(p)) {
			mToggleButton.activate(e);
		}
		
		if (mIsFullVisible) {
			// Loop through the bounding buttons for the inventory items
			for (Button b : mInvButtons) {
				if (b.contains(p)) {
					b.activate(e);
				}
			}
			
			for (EquipLocation loc : mEquipBounds.keySet()) {
				Rectangle rect = mEquipBounds.get(loc);
				
				if (rect.contains(p)) {
					// attempt to unequip it
					MouseListener list = mEquippedListeners.get(loc);
					if (list != null) {
						list.mouseClicked(e);
					}
					
				}
			}
		}
	}
	
	public void setEquippedItems(EnumMap<EquipLocation, TakeableItem> equippedItems, Map<EquipLocation, MouseListener> listeners) {
		mEquippedItems = equippedItems;
		mEquippedListeners = listeners;
	}
	
	
	/**
	 * Helper method to avoid calculations unless they are really
	 * needed as there are a lot of them. Do not belong in paint()
	 */
	private void calculateBounds() {
		mBounds = new Rectangle(mPaddingLeft,
										mPaddingTop,
										this.getWidth() - mPaddingRight - mPaddingLeft,
										this.getHeight() - mPaddingBottom - mPaddingTop);
		
		// Divide the bounding rectangle into two pieces, one for equipment and one for inventory
		mEquipRect = new Rectangle(mBounds.x, mBounds.y,
											mBounds.width / 2, mBounds.height);
		mInvRect = new Rectangle(mBounds.x + (mBounds.width / 2), mBounds.y,
											mBounds.width / 2, mBounds.height);
		
		
		int buttonWidth = 200;
		int buttonHeight = 20;
		mToggleButton.setBounds(this.getWidth() / 2 - buttonWidth / 2, 0, buttonWidth, buttonHeight);
		
		buttonWidth = 75;
		buttonHeight = 50;
		// Next and Prev button
		mInvNextPageButton.setBounds(mInvRect.x + mInvRect.width - buttonWidth - 5,
								mInvRect.y + mInvRect.height - buttonHeight - 5,
								buttonWidth,
								buttonHeight);
		
		mInvPrevPageButton.setBounds(mInvRect.x + 5,
								mInvRect.y + mInvRect.height - buttonHeight - 5,
								buttonWidth,
								buttonHeight);
		
		
		// ==== Equipped Items ====
		int boxWidth = 75;
		int boxHeight = 75;
		
		int topPadding = 50;
		int boxVPadding = 8;
		int boxHPadding = 4;
		
		// Head
		boxWidth = 50;
		boxHeight = 50;
		Rectangle head = new Rectangle(mEquipRect.x + mEquipRect.width / 2 - boxWidth / 2,
										mEquipRect.y + topPadding,
										boxWidth,
										boxHeight);
		
		
		// Body
		boxWidth = 75;
		boxHeight = 75;
		Rectangle body = new Rectangle(mEquipRect.x + mEquipRect.width / 2 - boxWidth / 2,
										head.y + head.height + boxVPadding,
										boxWidth,
										boxHeight);
		
		boxWidth = 35;
		boxHeight = 65;
		// Weapon
		Rectangle weaponLeft = new Rectangle(body.x - boxHPadding - boxWidth,
										head.y + head.height + boxVPadding,
										boxWidth,
										boxHeight);
		
		// Weapon
		Rectangle weaponRight = new Rectangle(head.x - boxHPadding - boxWidth,
										head.y + head.height + boxVPadding,
										boxWidth,
										boxHeight);
		
		boxWidth = 35;
		boxHeight = 40;
		// Legs
		Rectangle legs = new Rectangle(mEquipRect.x + mEquipRect.width / 2 - boxWidth / 2,
										body.y + body.height + boxVPadding,
										boxWidth,
										boxHeight);
		
		// Mount
		boxHeight = 100;
		boxWidth = 175;
		Rectangle mount = new Rectangle(mEquipRect.x + mEquipRect.width / 2 - boxWidth / 2,
										mEquipRect.y + mEquipRect.height - boxHeight - boxVPadding,
										boxWidth,
										boxHeight);
			
		mEquipBounds.put(EquipLocation.HEAD, head);
		mEquipBounds.put(EquipLocation.BODY, body);
		mEquipBounds.put(EquipLocation.LEGS, legs);
		mEquipBounds.put(EquipLocation.WEAPON, weaponLeft);
		mEquipBounds.put(EquipLocation.MOUNT, mount);
		
		
		
		// === Inventory Items ===

		buttonWidth = mInvRect.width - 10;
		buttonHeight = 35;
		
		int buttonVPadding = 10;
		int buttonHPadding = 10;
		

		int xOffset = mInvRect.width / 2 - buttonWidth / 2;
		int yOffset = buttonVPadding*4;
		
		// Calculate the location for the item
		mInvButtons.clear();
		
//		for (int i = 0; i < inv.getSize(); i++) {
		for (TakeableItem ti : mInvItems.keySet()) {
			
			if (ti == null) continue;
			

			
			Button button = new Button(ti.getName());
			button.setBounds(mInvRect.x + xOffset,
							mInvRect.y + yOffset,
							buttonWidth,
							buttonHeight);
			
			button.setListener(mInvItems.get(ti));
			
			mInvButtons.add(button);
			
			yOffset += buttonVPadding + buttonHeight;
			
			
		}
		
		
	}

	@Override
	public Dimension getPreferredSize() {
		return (new Dimension(0, 0));
	}

	@Override
	public void resize(int width, int height) {
		super.resize(width, height);
		
		calculateBounds();
		updateInventory();
		
		// Invalidate as we have new bounds
		this.invalidate();
	}
	
	private void updateInventory() {
		if (mEntity == null) return;
		
		if (mInvRect == null || mEquipRect == null) {
			calculateBounds();
		}
		
	}

	
	public void showInventory() {
		mIsFullVisible = true;
		this.invalidate();
	}
	
	public void hideInventory() {
		mIsFullVisible = false;
		this.invalidate();
	}
	
	/**
	 * Toggles the visibility of the inventory
	 */
	public boolean toggleInventory() {
		if (mIsFullVisible) {
			hideInventory();
			
		}
		else {
			showInventory();
		}
		
		return (mIsFullVisible);
	}
	
	public void register(InventoryActionListener listener) {
		this.mListeners.add(listener);
	}
	
	public void unregister(InventoryActionListener listener) {
		this.mListeners.add(listener);
	}
	
	public interface InventoryActionListener {
		public void nextPage();
		public void prevPage();
	}
	
	public void setBackgroundImage(Image bg) {
		mBackgroundImage = bg;
	}
	
	public Image getBackgroundImage() {
		return (mBackgroundImage);
	}
	

}
